package com.ld.bisystem.util;

import lombok.SneakyThrows;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class ReflectionUtil {

	private static final String set_prefix = "set";

	private static final String get_prefix = "get";

	private static final String is_prefix = "is";

	public static final String sp_prefix = "\\.";

	public static boolean isNotEmpty(Object val) {
		return !isEmpty(val);
	}
		public static boolean isEmpty(Object val){
		if(val instanceof String){
			return val.toString().length() == 0;
		}else if(val instanceof List){
			List list = (List) val;
			return list.size() == 0;
		}else {
			return val == null;
		}
	}

	private static  boolean methodWhere(Method method,Class... clazz){
		int i = 0;
		for (Class<?> aClass : method.getParameterTypes()) {
			if(!aClass.isAssignableFrom(clazz[i++])){
				return false;
			}
		}
		return true;
	}


	@SneakyThrows
	public static Method findMethod(Class clazz,String name,Class... paramsClass){
		for (Method method : clazz.getMethods()) {
			if(method.getName().equals(name)){
				if(methodWhere(method,paramsClass)){
					return method;
				}
			}
		}
		return  null;
	}


	@SneakyThrows
	public static Object invokeMethod(Object obj,String name,Object... params) {

		Class[] clazzs = new Class[params.length];
		int i  = 0;
		for (Object param : params) {
			clazzs[i++] = param.getClass();
		}
		Method method =  findMethod(obj.getClass(),name,clazzs);
		method.setAccessible(true);
		try{
			return method.invoke(obj,params);
		}catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}



	public static Field findField(Class clazz,String name){
		return  ReflectionUtils.findField(clazz,name);
	}


	/**
	 * 得到所有字段
	 * @param clazz
	 * @return
	 */
	public static List<Field> getAllDeclaredFields(Class<?> clazz) {
		List<Field> list = new LinkedList<>();
		while(clazz != null) {
			for(Field field:clazz.getDeclaredFields()) {
				if(Modifier.isStatic(field.getModifiers())){
					continue;
				}
				list.add(field);
			}
			clazz = clazz.getSuperclass();
		}
		return list;
	}


	private static Method getGetMethod(Class clazz,String name){
		String methodName =get_prefix + StringUtil.toUpperCaseFirstOne(name);
		Method method = ReflectionUtils.findMethod(clazz,methodName);

		return method;
	}
	private static Method getSetMethod(Class clazz,String name){
		String methodName =set_prefix + StringUtil.toUpperCaseFirstOne(name);
		for (Method method : clazz.getMethods()) {
			if(method.getName().equals(methodName)){
				return method;
			}
		}


		return null;
	}




	public static <E> E newInstance(Class<E> cla){
		try{
			return cla.newInstance();
		}catch (Exception e){
			throw new RuntimeException("实例化异常:"+cla);
		}

	}

  public static <E> E invokeGetter(Object obj, String[] names) {
		return invokeGetter(obj,Arrays.asList(names));
  }
		/**
         * 调用Getter方法.
         * 支持多级，如：对象名.对象名.方法
         */
	public static <E> E invokeGetter(Object obj, List<String> names) {
		Object object = obj;
		for (String name : names){

			if(object.getClass().isArray()){
				Object[] args =  (Object[])object;
				object = args[Integer.parseInt(name)];
			}else if(object instanceof List){
				List list = (List) object;
				object= list.get(Integer.parseInt(name));
			} else if(object instanceof  Map){
				Map map = (Map)object;
				object = map.get(name);
			}else{
				Method method = getGetMethod(object.getClass(),name);

				method.setAccessible(true);
				object = ReflectionUtils.invokeMethod(method,object);
			}

		}
		return (E)object;
	}

	/**
	 * 调用Getter方法.
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static <E> E invokeGetter(Object obj, String propertyName) {
		String[] names = propertyName.split(sp_prefix);
		return (E)invokeGetter(obj,names);
	}
	/**
	 * 调用Setter方法, 仅匹配方法名。
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static void invokeSetter(Object obj, String propertyName, Object value) {
		Object object = obj;
		String[] names = propertyName.split(sp_prefix);
		String key = names[names.length-1];
		if(names.length >=2){
			String[] keys = new String[names.length - 1];
			for (int i = 0;i<names.length - 1;i++){
				keys[i]=names[i];
			}
			object = invokeGetter(obj,keys);
		}
		if(object.getClass().isArray()){
			Object[] args =  (Object[])object;
			args[Integer.parseInt(key)] = value;
		}else if(object instanceof List){
			List list = (List) object;
			list.add(Integer.parseInt(key),value);
		} else if(object instanceof  Map){
			Map map = (Map)object;
			map.put(key,value);
		}else{
			Method method=getSetMethod(object.getClass(),key);

			method.setAccessible(true);


			ReflectionUtils.invokeMethod(method,object,value);

		}

	}




}